package gee

import (
	"log"
	"net/http"
	"strings"
)

/**
 * node 中的 pattern 是: /article/:id/info   加上method可以组成handlers map中的 key: GET-/article/:id/info
 * Context 中的 pattern 是: /article/1001/info 是具体的url-path,可以从中提取出param的value
 */

type router struct {
	// eg: roots["GET"] = node;  roots["POST"] = node
	roots map[string]*node

	// eg: handlers["GET-/article/:id/info"] = func
	handlers map[string]HandlerFunc // container to resolve http route
}

func newRouter() *router {
	return &router{
		roots:    make(map[string]*node),
		handlers: make(map[string]HandlerFunc),
	}
}

// parsePattern
// @Description: 分割待匹配的路由为分段
// @receiver r
// @param pattern string
// @return []string
func (r *router) parsePattern(pattern string) []string {
	patternParts := strings.Split(pattern, "/")

	parts := make([]string, 0)
	for _, part := range patternParts {
		if part == "" {
			continue
		}
		parts = append(parts, part)
		if part[0] == '*' {
			// 模糊匹配
			break
		}
	}

	// / => parts=[]
	// /hello => parts=["hello"]
	return parts
}

// addRoute
// @Description: 添加路由到 trie 树
// @receiver r *router
// @param method string
// @param pattern string
// @param handler HandlerFunc
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
	log.Printf("Route %-7s - %s", method, pattern)

	parts := r.parsePattern(pattern)
	key := method + "-" + pattern

	if _, ok := r.roots[method]; !ok {
		// 未存在之前的路由
		r.roots[method] = &node{} // root的 pattern 是"/"
	}

	r.roots[method].insert(pattern, parts, 0)
	r.handlers[key] = handler
}

// getRoute
// @Description: 从 trie 树中匹配出路由节点
// @receiver r *router
// @param method string
// @param path string
// @return *node
// @return map[string]string
func (r *router) getRoute(method string, path string) (node *node, param map[string]string) {
	root, ok := r.roots[method]
	if !ok {
		return nil, nil
	}

	// http 请求中的 path 分段
	pathParts := r.parsePattern(path)
	n := root.search(pathParts, 0)
	if n == nil {
		return nil, nil
	}

	// 找到了对应节点,解析出对应的参数
	parts := r.parsePattern(n.pattern) // 路由中的分段,用来当变量
	params := make(map[string]string)

	for i, part := range parts {
		if part[0] == ':' {
			// :lang
			params[part[1:]] = pathParts[i]
		}
		if part[0] == '*' && len(part) > 1 {
			// *filepath  => params[filepath] = css/home/index.css
			params[part[1:]] = strings.Join(pathParts[i:], "/")
			break
		}
	}

	// 返回匹配到的路由节点 和 参数
	return n, params
}

// handle
// @Description: 解析路由,处理请求
// @receiver r *router
// @param ctx *Context
func (r *router) handle(ctx *Context) {
	// trie 树搜索匹配路由
	lastNode, param := r.getRoute(ctx.Method, ctx.Path)
	if lastNode == nil {
		ctx.handlers = append(ctx.handlers, func(ctx *Context) {
			ctx.String(http.StatusNotFound, "404 Not Found: %q\n", ctx.Path)
		})
	} else {
		// 匹配到路由,则将param放入context
		ctx.Params = param
		key := ctx.Method + "-" + lastNode.pattern // GET-/article/:id/info
		// handle request
		ctx.handlers = append(ctx.handlers, r.handlers[key])
	}

	ctx.Next()
}
